import fs from 'fs'
import path from 'path'
import {
  wrapFn
} from './share/index'

import * as methodList from './uni-id'

let createConfig
try {
  createConfig = require('uni-config-center')
} catch (error) { }

const configTips = '\n传入配置的方式有以下几种：\n- 在uni-config-center公共模块的uni-id目录下放置config.json文件（推荐）\n- 在uni-id公共模块的目录下放置config.json文件\n- 使用init方法传入配置\n- 如果使用uni-config-center且HBuilderX版本低于3.1.8，批量上传云函数及公共模块后需要再单独上传一次uni-id'
class UniID {
  constructor ({
    context,
    config
  } = {}) {
    const pluginConfig = createConfig && createConfig({
      pluginId: 'uni-id'
    })
    this.pluginConfig = pluginConfig
    this.config = config || this._getConfigContent()
    // 兼容旧uni-id逻辑（非开发者调用createInstance创建），防止__ctx__被缓存在uni-id内部
    // this.context = context
    Object.defineProperty(this, 'context', {
      get () {
        return context || global.__ctx__
      }
    })
    // keys: customToken
    this.interceptorMap = new Map()
    if (pluginConfig && pluginConfig.hasFile('custom-token.js')) {
      this.setInterceptor('customToken', require(pluginConfig.resolve('custom-token.js')))
    }
  }

  _getConfigContent () {
    // 使用uni-config-center
    if (this.pluginConfig && this.pluginConfig.hasFile('config.json')) {
      this._hasConfigFile = true
      try {
        return this.pluginConfig.config()
      } catch (error) {
        return
      }
    }
    const configFilePath = path.resolve(__dirname, 'config.json')
    this._hasConfigFile = fs.existsSync(configFilePath)
    try {
      return require(configFilePath)
    } catch (error) { }
  }

  init (config) {
    this.config = config
  }

  setInterceptor (timing, handler) {
    this.interceptorMap.set(timing, handler)
  }

  _getConfig (platform) {
    const hasConfig = this.config && Object.keys(this.config).length !== 0
    if (this._hasConfigFile && !hasConfig) {
      throw new Error('请确保公用模块uni-id对应的配置文件格式正确（不可包含注释）' + configTips)
    } else if (!hasConfig) {
      throw new Error('公用模块uni-id缺少配置信息' + configTips)
    }
    const platformConfig = Object.assign(this.config, this.config[platform || this.context.PLATFORM]) || {}
    const defaultConfig = {
      bindTokenToDevice: false,
      tokenExpiresIn: 7200,
      tokenExpiresThreshold: 1200,
      passwordErrorLimit: 6,
      passwordErrorRetryTime: 3600,
      usernameToLowerCase: true,
      emailToLowerCase: true
    }
    const config = Object.assign(defaultConfig, platformConfig)
    const argsRequired = ['passwordSecret', 'tokenSecret', 'tokenExpiresIn', 'passwordErrorLimit', 'passwordErrorRetryTime']
    argsRequired.forEach((item) => {
      if (!config || !config[item]) {
        throw new Error(`请在公用模块uni-id的配置信息中内添加配置项：${item}`)
      }
    })
    return config
  }
}

for (const key in methodList) {
  UniID.prototype[key] = wrapFn(methodList[key])
}

function createInstance ({
  context,
  config
} = {}) {
  const uniIDOrigin = new UniID({
    context,
    config
  })
  const uniID = new Proxy(uniIDOrigin, {
    get (target, prop) {
      if (prop in target) {
        if (typeof target[prop] === 'function') {
          return target[prop].bind(uniID)
        } else {
          return target[prop]
        }
      }
      return undefined
    }
  })
  return uniID
}

UniID.prototype.createInstance = createInstance

export default createInstance()
